//
//  SoundPlayer.swift
//  Social
//
//  Created by 李响 on 2019/5/30.
//  Copyright © 2019 shengsheng. All rights reserved.
//

import UIKit
import AVFoundation

class SoundPlayer: NSObject {
    
    private static let shared = SoundPlayer()
    
    /// 可禁用声音
    static var enabled: Bool = true
    
    fileprivate var items: [SoundPlayerItem] = []
    
    /// 播放声音
    ///
    /// - Parameters:
    ///   - url: url
    ///   - loop: 循环
    static func play(url: URL, loop: Bool = false) throws {
        guard enabled else { return }
        
        let item = try SoundPlayerItem(url: url)
        item.delegate = shared
        item.set(loop: loop ? -1 : 0)
        item.set(volume: 0.9)
        item.play()
        
        shared.items.append(item)
    }
    
    static func stop(url: URL? = nil) {
        if let url = url {
            shared.items.removeAll {
                guard $0.url == url else { return false }
                $0.stop()
                return true
            }
            
        } else {
            shared.items.removeAll {
                $0.stop()
                return true
            }
        }
    }
}

extension SoundPlayer: SoundPlayerItemDelegate {
    
    func finish(item: SoundPlayerItem) {
        items.removeAll { $0 == item }
    }
}

protocol SoundPlayerItemDelegate: NSObjectProtocol {
    func finish(item: SoundPlayerItem)
}

class SoundPlayerItem: NSObject, AVAudioPlayerDelegate {
    
    weak var delegate: SoundPlayerItemDelegate?
    
    let url: URL
    var isBackground: Bool = false
    
    private var player: AVAudioPlayer?
    private var deviceCurrentTime: TimeInterval?
    
    init(url: URL) throws {
        self.url = url
        super.init()
        
        let player = try AVAudioPlayer(contentsOf: url)
        player.volume = 1.0
        player.numberOfLoops = 0
        player.delegate = self
        self.player = player
        
        setupNotification()
    }
    
    private func setupNotification() {
        
        NotificationCenter.default.addObserver(
            self,
            selector: #selector(willEnterForeground),
            name: UIApplication.willEnterForegroundNotification,
            object: nil
        )
        NotificationCenter.default.addObserver(
            self,
            selector: #selector(didEnterBackground),
            name: UIApplication.didEnterBackgroundNotification,
            object: nil
        )
    }
    
    @objc
    func willEnterForeground() {
        guard isBackground == false else {
            return
        }
        guard
            let player = player,
            let deviceLastTime = deviceCurrentTime else {
            return
        }
        
        player.play()
        let delay = player.deviceCurrentTime - deviceLastTime
        player.currentTime = player.currentTime + delay
        deviceCurrentTime = 0
    }
    
    @objc
    func didEnterBackground() {
        guard isBackground == false else {
            return
        }
        guard let player = player else {
            return
        }
        
        player.pause()
        deviceCurrentTime = player.deviceCurrentTime
    }
    
    public func play() {
        player?.play()
    }
    
    public func stop() {
        player?.delegate = nil
        player?.stop()
    }
    
    public func set(loop: Int) {
        player?.numberOfLoops = loop
    }
    
    public func set(volume: Float) {
        player?.volume = volume
    }
    
    internal func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) {
        player.delegate = nil
        delegate?.finish(item: self)
    }
}

